package com.dex4d.ui.qr.model;

import android.app.Activity;
import android.text.TextUtils;

import com.dex4d.BuildConfig;
import com.dex4d.R;
import com.dex4d.constants.IConstants;
import com.dex4d.core.http.DefaultTransformer;
import com.dex4d.core.http.JsonApiWrapper;
import com.dex4d.core.subscribers.ProgressSubscriber;
import com.dex4d.model.HttpResult;
import com.dex4d.model.RequestParam;
import com.dex4d.model.User;
import com.dex4d.ui.main.model.Dex4dTrade;
import com.dex4d.ui.main.model.TokenContract;
import com.dex4d.ui.qr.utils.AddressUtils;

import org.web3j.utils.Convert;
import org.web3j.utils.Numeric;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import rx.Observable;
import rx.Subscriber;
import rx.functions.Func1;
import rx.functions.Func2;

/**
 * 作者    LiQingyi
 * 时间    2018/11/20 18:31
 * 文件    dex4d-android
 * 描述    扫码支付相关操作
 */
public class QRPay {

    private Activity activity;
    private PayData payData;

    private OnQRPayListener payListener;

    public QRPay(Activity activity, OnQRPayListener payListener) {
        this.activity = activity;
        this.payListener = payListener;
    }

    public PayData getPayData() {
        return payData;
    }

    public void setTxHash(String hash) {
        payData.txHash = hash;
    }

    /**
     * 签名URL
     *
     * @param url
     * @return
     */
    private String signURL(String url) {
        try {
            URLParser parser = new URLParser(url);
            String address = parser.getParam("address");
            String nonce = parser.getParam("nonce");
            StringBuilder builder = new StringBuilder();
            builder.append(address).append("&").append(nonce).append("&").append(AddressUtils.getMD5Key(activity));
            String sign = parser.getParam("sign");
            String newSign = AddressUtils.md5(builder.toString());
            return url.replace(sign, newSign);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return BuildConfig.QR_URL_API;
    }

    /**
     * 更新签名URL
     *
     * @param url
     * @return
     */
    private Observable<String> updateSignURL(final String url) {
        return Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> subscriber) {
                String signStr = signURL(url);
                if (TextUtils.isEmpty(signStr)) {
                    subscriber.onError(new Throwable("Signature error"));
                } else {
                    subscriber.onNext(signStr);
                    subscriber.onCompleted();
                }
            }
        });
    }

    /**
     * 获取交易信息
     *
     * @param url
     */
    public void payInfo(String url) {

        final RequestParam gasParam = new RequestParam();
        gasParam.setId(2);
        gasParam.setJsonrpc(IConstants.JSON_RPC_VERSION);
        gasParam.setMethod(IConstants.CONTRACTSERVICE_GASPRICE);
        final List<String> address = Collections.singletonList(User.getInstance().getAddress());
        gasParam.setParams(address);

        //gas price
        Observable<HttpResult<String>> gasPriceObservable =
                JsonApiWrapper
                        .serviceApi()
                        .requestByParam(gasParam);

        Observable<QRResult> infoObservable = updateSignURL(url)
                .flatMap(new Func1<String, Observable<QRResult>>() {
                    @Override
                    public Observable<QRResult> call(String paramUrl) {//获取交易信息
                        return JsonApiWrapper
                                .serviceApi()
                                .QRPay(paramUrl);
                    }
                });

        Observable.zip(infoObservable
                , gasPriceObservable
                , new Func2<QRResult, HttpResult<String>, QRResult>() {
                    @Override
                    public QRResult call(QRResult result, HttpResult<String> stringHttpResult) {
                        String gasPrice = stringHttpResult.getResult();
                        String fee = Numeric.decodeQuantity(result.paydata.gasLimit)
                                .multiply(new BigInteger(gasPrice))
                                .toString();
                        String feeEth = Convert.fromWei(fee, Convert.Unit.ETHER)
                                .setScale(6, BigDecimal.ROUND_DOWN)
                                .toString() + "ETH";
                        result.paydata.txFee = feeEth;
                        return result;
                    }
                })
                .compose(new DefaultTransformer<QRResult>())
                .subscribe(new ProgressSubscriber<QRResult>(activity, true) {
                    @Override
                    public void onNext(QRResult result) {
                        if (result.isOk()) {
                            if (TextUtils.equals(User.getInstance().getAddress().toLowerCase(),
                                    result.paydata.account.toLowerCase())) {//判断是否为同意账户
                                payData = result.paydata;
                                payListener.payInfo(result);
                            } else {
                                String error = activity.getResources().getString(R.string.dialog_tips_error_13);
                                payListener.error(new QRResult(new QRResult.Error(error)));
                            }
                        } else {//失败
                            payListener.payInfo(result);
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        super.onError(e);
                        payListener.error(new QRResult(new QRResult.Error()));
                    }
                });
    }

    /**
     * 确认支付签名
     *
     * @param url
     */
    public void payConfirm(final String url) {
        createTrade(payData, url)
                .compose(new DefaultTransformer<Dex4dTrade>())
                .subscribe(new ProgressSubscriber<Dex4dTrade>(activity, false) {
                    @Override
                    public void onNext(Dex4dTrade trade) {
                        if (TextUtils.equals(trade.getQrDesc(), "buy") || TextUtils.equals(trade.getQrDesc(), "reinvest")) {//买入 ok
                            //以太坊购买
                            if (TextUtils.equals(trade.getSymbol(), Dex4dTrade.ETH)) {
                                trade.buy(trade.getCoinAmount(), trade.getReferral());
                            }
                            //其他代(ERC20)币购买
                            else {
                                trade.approve(trade.getCoinAmount());
                            }
                        } else if (TextUtils.equals(trade.getQrDesc(), "buyreferral")) {//???
                            trade.buyReferral(Convert.fromWei(trade.getCoinAmount(), Convert.Unit.ETHER).toString(), trade.getReferral());
                        } else if (TextUtils.equals(trade.getQrDesc(), "sell")) {//卖出 ok
                            trade.sell(Convert.fromWei(trade.getCoinAmount(), Convert.Unit.ETHER).toString());
                        } else if (TextUtils.equals(trade.getQrDesc(), "swap")) {//对倒 ok
                            trade.swap(trade.getSwapTo(), Convert.fromWei(trade.getCoinAmount(), Convert.Unit.ETHER).toString());
                        } else if (TextUtils.equals(trade.getQrDesc(), "withdraw")) {//TODO 提现
                            trade.withdraw(trade.getSymbol(), Convert.fromWei(trade.getCoinAmount(), Convert.Unit.ETHER).toString());
                        } else if (TextUtils.equals(trade.getQrDesc(), "buyswap")) {//???buyswap
                            trade.buyArbitrage(Convert.fromWei(trade.getCoinAmount(), Convert.Unit.ETHER).toString());
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        super.onError(e);
                        payListener.error(new QRResult(new QRResult.Error(e.getMessage())));
                    }
                });
    }

    /**
     * 创建交易签名工具类
     *
     * @param txInfo 扫码获取的支付信息
     * @param url    请求URL
     * @return
     */
    private Observable<Dex4dTrade> createTrade(final PayData txInfo, final String url) {

        //1支付相关信息
        final PayData payData = txInfo;//交易信息

        //2获取合约相关信息
        final RequestParam requestParamTables = new RequestParam();
        requestParamTables.setId(2);
        requestParamTables.setJsonrpc(IConstants.JSON_RPC_VERSION);
        requestParamTables.setMethod(IConstants.GATEWAY_GETTOKENTABLES);
        requestParamTables.setParams(new ArrayList<String>());
        return JsonApiWrapper
                .serviceApi()
                .getTokenTables(requestParamTables)//判断当前代币的状态
                .map(new Func1<HttpResult<List<TokenContract>>, Dex4dTrade>() {
                    @Override
                    public Dex4dTrade call(HttpResult<List<TokenContract>> result) {
                        Dex4dTrade trade = new Dex4dTrade(activity, payData.symbol);
                        trade.setPlatform(Dex4dTrade.P_WEB_QR);
                        trade.setQrDesc(payData.desc);
                        trade.setQrURl(url);
                        trade.setQrPayListener(payListener);
                        for (TokenContract temp : result.getResult()) {
                            if (TextUtils.equals(trade.getSymbol(), temp.name)) {
                                if (TextUtils.equals(trade.getSymbol(), Dex4dTrade.ETH)) {
                                    trade.setSpenderAddress(temp.dealer_addr);
                                    trade.setTokenContractAddress(BuildConfig.CONTRACT_DEX4D_PROTOCOL);
                                } else {
                                    trade.setSpenderAddress(temp.dealer_addr);
                                    trade.setTokenContractAddress(temp.token_addr);
                                }
                                break;
                            }
                        }

                        //TODO 其他操作数量设置可以根据操作类型进行相关设置

                        trade.setCoinAmount(Convert.toWei(payData.amountA, Convert.Unit.ETHER).setScale(0).toString());//花费数量
                        trade.setTokenAmount(payData.amountB);//预估数量

                        trade.setSwapFrom(payData.swapA);
                        trade.setSwapTo(payData.swapB);

                        //设置推荐
                        if (TextUtils.isEmpty(payData.referrer)) {
                            trade.setReferral(BuildConfig.ADDRESS_X0);
                        } else {
                            trade.setReferral(payData.referrer);
                        }

                        //TODO 推荐人操作可以增加相关属性设置

                        return trade;
                    }
                });
    }

    /**
     * 拒绝签名
     *
     * @param url
     * @return
     */
    public void payReject(final String url) {
        Observable
                .create(new Observable.OnSubscribe<QRRequest>() {
                    @Override
                    public void call(Subscriber<? super QRRequest> subscriber) {
                        QRRequest request = QRRequest.createPayRequest(url, false);
                        request.txdata = "";
                        StringBuilder builder = new StringBuilder();
                        builder.append(request.address).append("&");
                        builder.append(request.nonce).append("&");
                        builder.append(request.confirm).append("&");
                        builder.append(request.txdata).append("&");
                        builder.append(AddressUtils.getMD5Key(activity));
                        String newSign = AddressUtils.md5(builder.toString());
                        request.sign = newSign;
                        if (TextUtils.isEmpty(newSign)) {
                            subscriber.onError(new Throwable("Signature error"));
                        } else {
                            subscriber.onNext(request);
                            subscriber.onCompleted();
                        }
                    }
                })
                .flatMap(new Func1<QRRequest, Observable<QRResult>>() {
                    @Override
                    public Observable<QRResult> call(QRRequest request) {
                        return JsonApiWrapper
                                .serviceApi()
                                .QRPayConfirm(BuildConfig.QR_URL_API + "/qrpay_confirm", request);
                    }
                })
                .compose(new DefaultTransformer<QRResult>())
                .subscribe(new ProgressSubscriber<QRResult>(activity, true) {
                    @Override
                    public void onNext(QRResult result) {
                        if (result.isOk()) {//失败
                            payListener.reject(result);
                        } else {
                            payListener.reject(result);
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        super.onError(e);
                        payListener.error(new QRResult(new QRResult.Error(e.getMessage())));
                    }
                });
    }

    public interface OnQRPayListener {
        /**
         * 支付成功
         *
         * @param result
         */
        void success(QRResult result);

        /**
         * 支付错误
         *
         * @param result
         */
        void error(QRResult result);

        /**
         * 获取支付信息
         *
         * @param result
         */
        void payInfo(QRResult result);

        /**
         * 拒绝
         *
         * @param result
         */
        void reject(QRResult result);
    }

}
